<?php

namespace common\components\paymch;

/**
 * 在线支付客户端
 *
 * @author emhome<emhome@163.com>
 * @since 2.0
 */
class MchClient {

    //应用ID
    public $appId;
    //私钥文件路径
    public $rsaPrivateKeyFilePath;
    //私钥值
    public $rsaPrivateKey;
    //接口网关地址
    public $gatewayUrl = "https://paymch.sghome.com/trade/create";
    //返回数据格式
    public $format = "json";
    //版本
    public $apiVersion = "1.0";
    // 表单提交字符集编码
    public $postCharset = "UTF-8";
    private $fileCharset = "UTF-8";
    //签名类型
    public $signType = "RSA2";

    public function render($params) {
        $params['app_id'] = $this->appId;
        $params['charset'] = $this->postCharset;
        $params['version'] = $this->apiVersion;
        $sign = $this->generateSign($params, $this->signType);
        $params['sign'] = $sign;
        $params['sign_type'] = $this->signType;
        return $this->curl($this->gatewayUrl, $params);
    }

    //used
    public function generateSign($params, $signType = "RSA") {
        $signData = $this->getSignContent($params);
        return $this->sign($signData, $signType);
    }

    //used
    private function getSignContent($params) {
        ksort($params);
        $stringToBeSigned = "";
        $i = 0;
        foreach ($params as $k => $v) {
            if (false === MchUtils::checkEmpty($v) && "@" != substr($v, 0, 1)) {
                //转换成目标字符集
                $v = MchUtils::characet($v, $this->postCharset, $this->fileCharset);
                if ($i == 0) {
                    $stringToBeSigned .= "$k" . "=" . "$v";
                } else {
                    $stringToBeSigned .= "&" . "$k" . "=" . "$v";
                }
                $i++;
            }
        }
        unset($k, $v);
        return $stringToBeSigned;
    }

    private function sign($data, $signType = "RSA") {
        $res = MchUtils::getPrivateKey($this->rsaPrivateKeyFilePath, $this->rsaPrivateKey);
        if (!$res) {
            die('您使用的私钥格式错误，请检查RSA私钥配置');
        }
        if ($signType == "RSA2") {
            openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
        } else {
            openssl_sign($data, $sign, $res);
        }
        if (!MchUtils::checkEmpty($this->rsaPrivateKeyFilePath)) {
            openssl_free_key($res);
        }
        return base64_encode($sign);
    }

    protected function curl($url, $param) {
        $ch = curl_init();
        if (stripos($url, "https://") !== FALSE) {
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        }
        if (is_string($param)) {
            $strPOST = $param;
        } else {
            $aPOST = array();
            foreach ($param as $key => $val) {
                $aPOST[] = $key . "=" . urlencode($val);
            }
            $strPOST = join("&", $aPOST);
        }

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $strPOST);
        $sContent = curl_exec($ch);
        $aStatus = curl_getinfo($ch);
        curl_close($ch);
        if (intval($aStatus["http_code"]) == 200) {
            return $sContent;
        } else {
            return false;
        }
    }

    protected function curls($url, $postFields = null) {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_FAILONERROR, false);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        $postBodyString = "";
        $encodeArray = array();
        $postMultipart = false;
        if (is_array($postFields) && 0 < count($postFields)) {
            foreach ($postFields as $k => $v) {
                if ("@" != substr($v, 0, 1)) {
                    //判断是不是文件上传
                    $postBodyString .= "$k=" . urlencode(MchUtils::characet($v, $this->postCharset, $this->fileCharset)) . "&";
                    $encodeArray[$k] = MchUtils::characet($v, $this->postCharset, $this->fileCharset);
                } else {
                    //文件上传用multipart/form-data，否则用www-form-urlencoded
                    $postMultipart = true;
                    $encodeArray[$k] = new \CURLFile(substr($v, 1));
                }
            }
            unset($k, $v);
            curl_setopt($ch, CURLOPT_POST, true);
            if ($postMultipart) {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $encodeArray);
            } else {
                curl_setopt($ch, CURLOPT_POSTFIELDS, substr($postBodyString, 0, -1));
            }
        }
        if ($postMultipart) {
            $headers = array('content-type: multipart/form-data;charset=' . $this->postCharset . ';boundary=' . $this->getMillisecond());
        } else {
            $headers = array('content-type: application/x-www-form-urlencoded;charset=' . $this->postCharset);
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        $reponse = curl_exec($ch);
        if (curl_errno($ch)) {
            throw new \yii\db\Exception(curl_error($ch), 0);
        } else {
            $httpStatusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if (200 !== $httpStatusCode) {
                throw new \yii\db\Exception($reponse, $httpStatusCode);
            }
        }
        curl_close($ch);
        return $reponse;
    }

}
